/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <set>
#include <cinttypes>
#include "wifi_common_util.h"
#include "wifi_lock_manager.h"
#include "wifi_logger.h"
#include "wifi_supplicant_hal_interface.h"
#include "wifi_service_manager.h"
#include "wifi_settings.h"
#include "system_ability_definition.h"
#include "connection_observer_client.h"
#include "app_mgr_client.h"
#include "app_mgr_interface.h"
#include "app_process_data.h"
#include "iservice_registry.h"

DEFINE_WIFILOG_LABEL("WifiLockManager");
namespace OHOS {
namespace Wifi {
constexpr const char *WIFI_APP_CHANGE_MGR_WORK_THREAD = "WIFI_APP_CHANGE_MGR_WORK_THREAD";
WifiLockManager* WifiLockManager::g_instance = nullptr;
std::mutex WifiLockManager::insMutex_;
WifiLockManager* WifiLockManager::GetInstance()
{
    if (g_instance == nullptr) {
        WIFI_LOGI("Instance is nullptr, New WifiLockManager instance");
        std::unique_lock<std::mutex> lock(insMutex_);
        if (g_instance == nullptr) {
            auto service = new (std::nothrow) WifiLockManager;
            g_instance = service;
        }
    }
    return g_instance;
}

WifiLockManager::WifiLockManager()
{
    appChangeEventRunner_ = AppExecFwk::EventRunner::Create(WIFI_APP_CHANGE_MGR_WORK_THREAD);
    if (!appChangeEventRunner_) {
        WIFI_LOGE("Create event runner failed.");
        return;
    }
    appChangeEventHandler_ = std::make_shared<AppExecFwk::EventHandler>(appChangeEventRunner_);
    if (appChangeEventHandler_) {
        std::function<void()> RegisterAppStateObserverFunc =
                            std::bind(&WifiLockManager::RegisterAppStateObserver, this);
        appChangeEventHandler_->PostSyncTask(RegisterAppStateObserverFunc);
    } else {
        WIFI_LOGE("Create event handler failed.");
    }
    WIFI_LOGI("Register app state observer successful.");
}

WifiLockManager::~WifiLockManager()
{
    if (appChangeEventRunner_) {
        appChangeEventRunner_->Stop();
        appChangeEventRunner_.reset();
    }
    if (appChangeEventHandler_) {
        appChangeEventHandler_.reset();
    }

     if (appStateObserver_) {
        delete appStateObserver_;
        appStateObserver_ = nullptr;
    }
}

void WifiLockManager::RegisterAppStateObserver()
{
    WIFI_LOGD("%{public}s called", __func__);
    auto appMgrClient = std::make_unique<AppExecFwk::AppMgrClient>();
    appStateObserver = new (std::nothrow) AppStateObserver();
    int regAppStatusObsRetry = 0;
    while (appMgrClient->ConnectAppMgrService() != AppExecFwk::AppMgrResultCode::RESULT_OK) {
        WIFI_LOGE("ConnectAppMgrService fail, try again! retryTimes=%{public}d", ++regAppStatusObsRetry);
    }
    auto systemAbilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    sptr<AppExecFwk::IAppMgr> appObject =
        iface_cast<AppExecFwk::IAppMgr>(systemAbilityManager->GetSystemAbility(APP_MGR_SERVICE_ID));
    if (appObject) {
        int ret = appObject->RegisterApplicationStateObserver(appStateObserver);
        if (ret == ERR_OK) {
            WIFI_LOGI("register application state observer success.");
            return;
        }
        WIFI_LOGE("register application state observer fail, ret = %{public}d", ret);
        return;
    }
    WIFI_LOGE("get SystemAbilityManager fail");
}

WifiMode WifiLockManager::GetLockMode() 
{
    int screenState = WifiSettings::GetInstance().GetScreenState();
    WIFI_LOGI("%{public}s screenState %{public}d", \
        __func__, screenState);

    if (screenState == MODE_STATE_OPEN) {
        return WIFI_MODE_FULL_HIGH_PERF;
    }
    if (refCount_ > 0 && !wifiLockBundles_.empty()) {
        return WIFI_MODE_FULL_HIGH_PERF;
    }
    return WIFI_MODE_NO_LOCKS_HELD;
}

bool WifiLockManager::ResetCurrentMode() 
{
    return true;
}

bool WifiLockManager::SetNewMode(WifiMode newLockMode)
{
    WIFI_LOGD("%{public}s Set to new mode %{public}d", __func__, static_cast<int>(newLockMode));
    switch (newLockMode) {
        case WIFI_MODE_FULL_HIGH_PERF: {
            if (WifiSupplicantHalInterface::GetInstance().WpaSetSuspendMode(false) != WIFI_IDL_OPT_OK) {
                WIFI_LOGE("Set suspend mode failed");
                return false;
            }
            lastLockTimeStamp_ = std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::steady_clock::now().time_since_epoch()).count();
            break;
        }
        case WIFI_MODE_NO_LOCKS_HELD: {
            if (WifiSupplicantHalInterface::GetInstance().WpaSetSuspendMode(true) != WIFI_IDL_OPT_OK) {
                WIFI_LOGE("Set suspend mode failed");
                return false;
            }
            break;
        }
        default: {
            WIFI_LOGE("Invalid new wifi mode:%{public}d ", static_cast<int>(newLockMode));
            return false;
        }
    }
    currentWifiMode_ = newLockMode;
    WIFI_LOGI("%{public}s Set new mode %{public}d successful.", __func__, static_cast<int>(newLockMode));
    return true;
}

}
}
